package net.tv90.bfmccore.helper;

import net.tv90.bfmccore.event.PlayerCountryChangeEvent;
import net.tv90.bfmccore.squad.Squad;
import org.bitterorange.flansmodslain.FlansModAPI;
import org.bitterorange.flansmodslain.models.EntitySoldierWrapper;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * BFMC使用权限来区别阵营,分别为bfmc.rgf,bfmc.pla,bfmc.usmc
 * 同时使用MCH模组的计分板机制来取消队友伤害
 */

public class FactionHelper {

    public enum EnumKit{
        ASS,REC,SUP,ENG
    }

    public enum EnumCountry{
        US,RU,CN,NoFaction
    }

    /**
     * 存储玩家的兵种
     */
    public static Map<String,String> playerKit = new HashMap<>();

    /**
     * 存储玩家的阵营
     */
    public static Map<String,String> playerCountry = new HashMap<>();


    public static String getAICountry(String name){
        if(name == null) return "NoFaction";
        switch (name){
            case "USMC": return "US";
            case "RGF" : return "RU";
            case "PLA" : return "CN";
        }
        return "NoFaction";
    }

    public static String getScoreBoardName(EnumCountry enumCountry) {
        switch (enumCountry){
            case US: {
                return "USMC";
            }
            case RU: {
                return "RGF";
            }
            case CN: {
                return "PLA";
            }
            case NoFaction: {
                return null;
            }
            default:
                throw new RuntimeException();
        }
    }

    public static void setCountry(Player p, EnumCountry enumCountry){
        switch (enumCountry){
            case US: {
                setCountry(p,"US");
                break;
            }
            case RU: {
                setCountry(p,"RU");
                break;
            }
            case CN: {
                setCountry(p,"CN");
                break;
            }
            case NoFaction: {
                setCountry(p,"NoFaction");
                break;
            }
            default:
                throw new RuntimeException();
        }
    }

    /**
     * 设置玩家的国家
     * @param p 玩家
     * @param country 国家名 RU/US/CN/NoFaction
     */
    public static void setCountry(Player p, String country) {
        int index = Squad.getSquadIndex(p);
        if (index != -1) {
            Squad.quit(p);
        }
        String oldCountry = getCountry2(p);
        String factionName;
        switch (country) {
            case "RU":
                if (p.hasPermission("bfmc.usmc"))  Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.usmc");
                if (p.hasPermission("bfmc.pla"))   Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.pla");
                if (!p.hasPermission("bfmc.rgf"))  Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission set bfmc.rgf");
                factionName = "RGF";
                break;
            case "US":
                if (p.hasPermission("bfmc.rgf"))   Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.rgf");
                if (p.hasPermission("bfmc.pla"))   Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.pla");
                if (!p.hasPermission("bfmc.usmc")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission set bfmc.usmc");
                factionName = "USMC";
                break;
            case "CN":
                if (p.hasPermission("bfmc.rgf"))   Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.rgf");
                if (p.hasPermission("bfmc.usmc"))  Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.usmc");
                if (!p.hasPermission("bfmc.pla"))  Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission set bfmc.pla");
                factionName = "PLA";
                break;
            case "NoFaction":
                if (p.hasPermission("bfmc.pla"))   Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.pla");
                if (p.hasPermission("bfmc.rgf"))   Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.rgf");
                if (p.hasPermission("bfmc.usmc"))  Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.usmc");
                factionName = "No Team";
                break;
            default:
                throw new RuntimeException();
        }
        playerCountry.put(p.getName(),country);
        Bukkit.dispatchCommand(Bukkit.getConsoleSender(),"scoreboard teams join " + factionName + " " + p.getName());
        Bukkit.getServer().getPluginManager().callEvent(new PlayerCountryChangeEvent(p,oldCountry,country));
    }

    /**
     * 设置玩家的兵种
     * @param p 玩家
     * @param faction 兵种名 ASS REC SUP ENG
     */
    public static void setFaction(Player p,String faction){
        switch (faction){
            case "ASS":{
                if(!p.hasPermission("bfmc.assault")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission set bfmc.assault");
                if(p.hasPermission("bfmc.recon")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.recon");
                if(p.hasPermission("bfmc.support")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.support");
                if(p.hasPermission("bfmc.engineer")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.engineer");
                break;
            }
            case "REC":{
                if(p.hasPermission("bfmc.assault")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.assault");
                if(!p.hasPermission("bfmc.recon")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission set bfmc.recon");
                if(p.hasPermission("bfmc.support")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.support");
                if(p.hasPermission("bfmc.engineer")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.engineer");
                break;
            }
            case "SUP":{
                if(p.hasPermission("bfmc.assault")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.assault");
                if(p.hasPermission("bfmc.recon")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.recon");
                if(!p.hasPermission("bfmc.support")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission set bfmc.support");
                if(p.hasPermission("bfmc.engineer")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.engineer");
                break;
            }
            case "ENG":{
                if(p.hasPermission("bfmc.assault")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.assault");
                if(p.hasPermission("bfmc.recon")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.recon");
                if(p.hasPermission("bfmc.support")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission unset bfmc.support");
                if(!p.hasPermission("bfmc.engineer")) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "lp user " + p.getName() + " permission set bfmc.engineer");
                break;
            }
            default: throw new RuntimeException();
        }
        playerKit.put(p.getName(),faction);
    }

    /**
     *
     * @param p 玩家
     * @return 获取玩家的阵营和兵种 格式:RUASS 如果没有 返回 NoFaction
     */
    @Deprecated
    public static String getFaction(Player p) {
        if (p.hasPermission("bfmc.rgf")) {
            if (p.hasPermission("bfmc.assault")) {
                return "RUASS";
            } else if (p.hasPermission("bfmc.recon")) {
                return "RUREC";
            } else if (p.hasPermission("bfmc.support")) {
                return "RUSUP";
            } else if (p.hasPermission("bfmc.engineer")) {
                return "RUENG";
            }
        } else if (p.hasPermission("bfmc.usmc")) {
            if (p.hasPermission("bfmc.assault")) {
                return "USASS";
            } else if (p.hasPermission("bfmc.recon")) {
                return "USREC";
            } else if (p.hasPermission("bfmc.support")) {
                return "USSUP";
            } else if (p.hasPermission("bfmc.engineer")) {
                return "USENG";
            }
        } else if (p.hasPermission("bfmc.pla")) {
            if (p.hasPermission("bfmc.assault")) {
                return "CNASS";
            } else if (p.hasPermission("bfmc.recon")) {
                return "CNREC";
            } else if (p.hasPermission("bfmc.support")) {
                return "CNSUP";
            } else if (p.hasPermission("bfmc.engineer")) {
                return "CNENG";
            }
        }
        return "NoFaction";
    }

    /**
     *
     * @param p 玩家
     * @return 获取玩家的国家 格式:RU 如果没有 返回 NoFaction
     */
    public static String getCountry2(Player p){
        return playerCountry.getOrDefault(p.getName(),"NoFaction");
    }

    /**
     * 获取AI的国家
     * @param p
     * @return
     */
    public static String getCountry2(EntitySoldierWrapper p){
        return getAICountry(p.getCountry());
    }

    /**
     *
     * @param p 玩家
     * @return 获取玩家的兵种 格式:ASS 如果没有 返回 ""
     */
    public static String getKit2(Player p){
        return playerKit.getOrDefault(p.getName(),"");
    }

    public static String getKit2(EntitySoldierWrapper p){
        return p.getFaction();
    }

    /**
     *
     * @param p 玩家
     * @return 获取玩家的阵营和兵种 格式:RUASS 如果没有 返回 NoFaction
     */
    public static String getFaction2(Player p){
        return getCountry2(p) + getKit2(p);
    }

    public static String getFaction2(EntitySoldierWrapper p){
        return getCountry2(p) + getKit2(p);
    }

    /**
     * 获取玩家兵种
     * @param p 玩家
     * @return 兵种 ASS REC SUP ENG 如果没有 返回 NoFaction
     */
    @Deprecated
    public static String getKit(Player p){
        if (p.hasPermission("bfmc.assault")) {
            return "ASS";
        } else if (p.hasPermission("bfmc.recon")) {
            return "REC";
        } else if (p.hasPermission("bfmc.support")) {
            return "SUP";
        } else if (p.hasPermission("bfmc.engineer")) {
            return "ENG";
        }
        return "NoFaction";
    }

    /**
     *
     * @param p 玩家
     * @return 获取玩家的国家 RU/US/CN/NoFaction
     */
    @Deprecated
    public static String getCountry(Player p) {
        if (p.hasPermission("bfmc.rgf")) {
            return "RU";
        } else if (p.hasPermission("bfmc.usmc")) {
            return "US";
        } else if (p.hasPermission("bfmc.pla")) {
            return "CN";
        }
        return "NoFaction";
    }

    public static String getCountry_Lang(String fac) {
        switch (fac) {
            case "RU": return "俄国";
            case "US": return "美国";
            case "CN": return "中国";
            default: return "无阵营";
        }
    }


    public static String getCountry_Lang2(String fac) {
        switch (fac) {
            case "RU": return "俄国地面军队";
            case "US": return "美国海军陆战队";
            case "CN": return "中国人民解放军";
            default: return "无阵营";
        }
    }

    /**
     *
     * @param p 玩家
     * @return 获取该玩家的队友列表，除玩家自己之外
     */
    public static List<Player> getTeammates(Player p) {
        List<Player> list = getTeamer(p);
        list.remove(p);
        return list;
    }

    /**
     *
     * @param p 玩家
     * @return 获取该玩家的队友列表，包括玩家自己
     */
    public static List<Player> getTeamer(Player p) {
        String country = getCountry2(p);
        List<Player> list = new ArrayList<>();
        for (Player players : Bukkit.getOnlinePlayers()) {
            String allCountry = getCountry2(players);
            if (country.equals(allCountry)) list.add(players);
        }
        return list;
    }

    /**
     *
     * @param p AI
     * @return 获取该AI的玩家队友列表
     */
    public static List<Player> getTeamer(EntitySoldierWrapper p) {
        String country = getCountry2(p);
        List<Player> list = new ArrayList<>();
        for (Player players : Bukkit.getOnlinePlayers()) {
            String allCountry = getCountry2(players);
            if (country.equals(allCountry)) list.add(players);
        }
        return list;
    }


    /**
     * 根据国家获取玩家列表
     * @param country 国家 RU/US/CN/NoFaction
     * @return 玩家列表
     */
    public static List<Player> getPlayersFromCountry(String country){
        List<Player> list = new ArrayList<>();
        for (Player players : Bukkit.getOnlinePlayers()) {
            String allCountry = getCountry2(players);
            if (country.equals(allCountry)) list.add(players);
        }
        return list;
    }

    /**
     *
     * @param p 玩家
     * @return 获取该玩家的敌人列表
     */
    public static List<Player> getEnemies(Player p) {
        String country = getCountry2(p);
        List<Player> list = new ArrayList<>();
        for (Player players : Bukkit.getOnlinePlayers()) {
            String allCountry = getCountry2(players);
            if (!country.equals(allCountry)) list.add(players);
        }
        return list;
    }

    public static List<Entity> getEnemyEntities(Player p) {
        List<Entity> result = new ArrayList<>();
        List<Entity> e = p.getWorld().getEntities();
        for (Entity entity : e) {
            if(!(entity instanceof Player)) {
                if(FlansModAPI.isSoldier(entity) || FlansModAPI.isMCHeliAircraft(entity)) {
                    result.add(entity);
                }
            }
        }
        result.addAll(getEnemies(p));
        return result;
    }

    /**
     *
     * @param p AI
     * @return 获取该AI的玩家敌人列表
     */
    public static List<Player> getEnemies(EntitySoldierWrapper p) {
        String country = getCountry2(p);
        List<Player> list = new ArrayList<>();
        for (Player players : Bukkit.getOnlinePlayers()) {
            String allCountry = getCountry2(players);
            if (!country.equals(allCountry)) list.add(players);
        }
        return list;
    }

    /**
     *
     * @param p  玩家
     * @return 玩家阵营和兵种的中文翻译
     */
    public static String getFaction_Lang(Player p) {
        if(p.isOp()) return "管理员";
        String fac = getFaction2(p);
        switch (fac) {
            case "RUASS": return "俄国突击兵";
            case "RUREC": return "俄国侦察兵";
            case "RUSUP": return "俄国支援兵";
            case "RUENG": return "俄国工程兵";
            case "USASS": return "美国突击兵";
            case "USREC": return "美国侦察兵";
            case "USSUP": return "美国支援兵";
            case "USENG": return "美国工程兵";
            case "CNASS": return "中国突击兵";
            case "CNREC": return "中国侦察兵";
            case "CNSUP": return "中国支援兵";
            case "CNENG": return "中国工程兵";
        }
        return "无阵营";
    }

    /**
     *
     * @param p  AI
     * @return AI阵营和兵种的中文翻译
     */
    public static String getFaction_Lang(EntitySoldierWrapper p) {
        String fac = getFaction2(p);
        switch (fac) {
            case "RUASS": return "俄国突击兵";
            case "RUREC": return "俄国侦察兵";
            case "RUSUP": return "俄国支援兵";
            case "RUENG": return "俄国工程兵";
            case "USASS": return "美国突击兵";
            case "USREC": return "美国侦察兵";
            case "USSUP": return "美国支援兵";
            case "USENG": return "美国工程兵";
            case "CNASS": return "中国突击兵";
            case "CNREC": return "中国侦察兵";
            case "CNSUP": return "中国支援兵";
            case "CNENG": return "中国工程兵";
        }
        return "无阵营";
    }

    /**
     * 玩家1和玩家2是否在同一个世界
     * @param p1 玩家1
     * @param p2 玩家2
     * @return 是否在同一个世界
     */
    public static boolean isInSameWorld(Player p1, Player p2) {
        return p1.getWorld().getName().equals(p2.getWorld().getName());
    }

    public static boolean isInSameWorld(Entity p1, Entity p2) {
        return p1.getWorld().getName().equals(p2.getWorld().getName());
    }

    /**
     * 获取玩家视线范围内的敌人
     * @param player 玩家
     * @param distance 距离
     * @param angle 角度
     * @return 玩家列表
     */
    public static List<Player> getTargetEnemies(Player player, int distance, int angle) {
        List<Player> targetEnemies = new ArrayList<>();
        for (Player target : getEnemies(player)) {
            if (isInSameWorld(player, target) && target.getLocation().distance(player.getLocation()) <= distance) {
                if (isLookingAt(player, target, angle)) {
                    targetEnemies.add(target);
                }
            }
        }
        return targetEnemies;
    }

    public static List<Entity> getTargetEnemyEntities(Player player, int distance, int angle) {
        List<Entity> targetEnemies = new ArrayList<>();
        for (Entity target : getEnemyEntities(player)) {
            if (isInSameWorld(player, target) && target.getLocation().distance(player.getLocation()) <= distance) {
                if (isLookingAt(player, target, angle)) {
                    targetEnemies.add(target);
                }
            }
        }
        return targetEnemies;
    }

    /**
     * 获取玩家视线范围内的玩家
     * @param player 玩家
     * @param distance 距离
     * @param angle 角度
     * @return 玩家列表
     */
    public static List<Player> getTargetPlayers(Player player, int distance, int angle) {
        List<Player> targetPlayers = new ArrayList<>();
        for (Player target : Bukkit.getOnlinePlayers()) {
            if (isInSameWorld(player, target) && target.getLocation().distance(player.getLocation()) <= distance) {
                if (isLookingAt(player, target, angle) && isInSameWorld(player, target)) {
                    targetPlayers.add(target);
                }
            }
        }
        return targetPlayers;
    }


    public static double getNearestEnemyDistance(Player p, Location location, List<Player> enemies) {
        double result = Integer.MAX_VALUE;
        for (Player enemy : enemies) {
            if(isInSameWorld(p, enemy)) {
                double distance = location.distance(enemy.getLocation());
                if(distance < result) {
                    result = distance;
                }
            }
        }
        return result;
    }

    public static double getNearestTeammateDistance(Player p, Location location, List<Player> teammates) {
        double result = Integer.MAX_VALUE;
        for (Player teammate : teammates) {
            if(isInSameWorld(p, teammate)) {
                double distance = location.distance(teammate.getLocation());
                if(distance < result) {
                    result = distance;
                }
            }
        }
        return result;
    }

    public static double getFurthestEnemyDistance(Player p, Location location, List<Player> enemies) {
        double result = -1;
        for (Player enemy : enemies) {
            if(isInSameWorld(p, enemy)) {
                double distance = location.distance(enemy.getLocation());
                if(distance > result) {
                    result = distance;
                }
            }
        }
        return result;
    }


    /**
     * 玩家target 是否在玩家player 的视线范围内
     * @param player 玩家
     * @param target 目标玩家
     * @param angle 角度
     * @return 是否在视线范围内
     */
    private static boolean isLookingAt(Player player, Player target, int angle) {
        // 获取玩家的位置和朝向向量
        Vector playerDirection = player.getEyeLocation().getDirection();
        Vector targetDirection = target.getLocation().subtract(player.getEyeLocation()).toVector();
        // 单位化向量
        playerDirection.normalize();
        targetDirection.normalize();
        // 计算两个向量的点积
        double dotProduct = playerDirection.dot(targetDirection);
        // 将弧度转换为角度
        double angleDegrees = Math.toDegrees(Math.acos(dotProduct));
        // 检查夹角是否小于等于最大夹角
        boolean result = angleDegrees <= angle;

        if (hasObstacleBetweenPlayers(player, target)) {
            result = false;
        }

        return result;
    }

    private static boolean isLookingAt(Player player, Entity target, int angle) {
        // 获取玩家的位置和朝向向量
        Vector playerDirection = player.getEyeLocation().getDirection();
        Vector targetDirection = target.getLocation().subtract(player.getEyeLocation()).toVector();
        // 单位化向量
        playerDirection.normalize();
        targetDirection.normalize();
        // 计算两个向量的点积
        double dotProduct = playerDirection.dot(targetDirection);
        // 将弧度转换为角度
        double angleDegrees = Math.toDegrees(Math.acos(dotProduct));
        // 检查夹角是否小于等于最大夹角
        boolean result = angleDegrees <= angle;

        if (hasObstacleBetweenPlayerAndEntity(player, target)) {
            result = false;
        }

        return result;
    }


    /**
     * 检查两个玩家之间是否有障碍物
     * @param player1 玩家1
     * @param player2 玩家2
     * @return 是否有障碍物
     */
    public static boolean hasObstacleBetweenPlayers(Player player1, Player player2) {
        Location loc1 = player1.getEyeLocation();
        Location loc2 = player2.getEyeLocation();
        World world = loc1.getWorld();

        // 计算玩家之间的距离
        double distance = loc1.distance(loc2);
        Vector direction = new Vector(loc2.getX() - loc1.getX(), loc2.getY() - loc1.getY(), loc2.getZ() - loc1.getZ()).normalize();
        Vector increment = direction.multiply(0.1);
        Vector position = new Vector(loc1.getX(), loc1.getY(), loc1.getZ());

        // 检查路径
        for (int i = 0; i < distance * 10; i++) {
            position = position.add(increment);

            // 检查位置 + 0（脚下）到 + 1.5（头部）之间的区域
            for (double yOffset = 0; yOffset <= 1.5; yOffset += 0.5) {
                Block block = world.getBlockAt((int) position.getX(), (int) (position.getY() + yOffset), (int) position.getZ());
                if (!block.getType().isTransparent()) {
                    return true; // 发现非透明方块，路径被障碍物阻挡
                }
            }
        }

        return false; // 没有障碍物
    }


    public static boolean hasObstacleBetweenPlayerAndEntity(Player player1, Entity e) {
        Location loc1 = player1.getEyeLocation();
        Location loc2 = e.getLocation();
        World world = loc1.getWorld();

        double distance = loc1.distance(loc2);
        Vector direction = new Vector(loc2.getX() - loc1.getX(), loc2.getY() - loc1.getY(), loc2.getZ() - loc1.getZ()).normalize();
        Vector increment = direction.multiply(0.1);
        Vector position = new Vector(loc1.getX(), loc1.getY(), loc1.getZ());

        // 检查实体脚下和实体头部位置
        for (int i = 0; i < distance * 10; i++) {
            position = position.add(increment);

            // 检查实体脚下
            Block block1 = world.getBlockAt((int) position.getX(), (int) position.getY(), (int) position.getZ());
            if (!block1.getType().isTransparent()) {
                return true; // 实体脚下有障碍物
            }

            // 检查实体脚下 + 1.5格
            Block block2 = world.getBlockAt((int) position.getX(), (int) (position.getY() + 1.5), (int) position.getZ());
            if (!block2.getType().isTransparent()) {
                return true; // 实体头部（+1.5格）有障碍物
            }
        }
        return false;
    }


}
